from flask_restful import Resource, Api
from flask import request
from sqlalchemy import create_engine, inspect
from sqlalchemy.orm import sessionmaker
from models import Departments, Employees, DeptEmp, DeptManager, DeptManagerTitle, Titles  # noqa
from app import my_app
import config

api = Api(my_app)
engine = create_engine(config.BaseConfig.DATABASE_URI)
Session = sessionmaker(bind=engine)


def get_model_class(table_name):
    for cls in [Departments, Employees, DeptEmp, DeptManager, DeptManagerTitle, Titles]:
        if cls.__tablename__ == table_name:
            return cls
    return None


class Insert(Resource):
    def post(self, table_name):
        rows = request.json['rows']
        model = get_model_class(table_name)
        if model is None:
            return {'message': 'Invalid table name'}, 400
        with Session() as session:
            try:
                session.bulk_insert_mappings(model, rows)
                session.commit()
                return {'message': 'Insertion successful'}, 200
            except Exception as e:
                session.rollback()
                return {'message': str(e)}, 400
            finally:
                session.close()


class Update(Resource):
    def put(self, table_name):
        model = get_model_class(table_name)
        data = request.json
        if model is None:
            return {"message": "Invalid table name"}, 400
        with Session() as session:
            try:
                pk_names = [column.name for column in inspect(model).primary_key]
                pk = {pk_name: data.get(pk_name) for pk_name in pk_names}
                row = session.query(model).filter_by(**pk).first()
                if row is None:
                    return {"message": "Row not found"}, 400
                for key, value in data.items():
                    if key in pk_names:
                        continue
                    setattr(row, key, value)
                session.commit()
                return {'message': 'Update successful'}, 200
            except Exception as e:
                session.rollback()
                return {'message': str(e)}, 400
            finally:
                session.close()


class Delete(Resource):
    def delete(self, table_name, pks):
        model = get_model_class(table_name)
        if model is None:
            return {"message": "Invalid table name"}, 400
        with Session() as session:
            try:
                pk_names = [column.name for column in inspect(model).primary_key]
                pk_values = pks.split('/')
                if len(pk_names) != len(pk_values):
                    return {'message': 'Invalid primary key values'}, 400
                pk = dict(zip(pk_names, pk_values))
                row = session.query(model).filter_by(**pk).first()
                if row is None:
                    return {"message": "Row not found"}, 400
                session.delete(row)
                session.commit()
                return {'message': 'Delete successful'}, 200
            except Exception as e:
                session.rollback()
                return {'message': str(e)}, 400
            finally:
                session.close()


class Query(Resource):
    def get(self, table_name, pks):
        model = get_model_class(table_name)
        if model is None:
            return {"message": "Invalid table name"}, 400
        with Session() as session:
            try:
                pk_names = [column.name for column in inspect(model).primary_key]
                pk_values = pks.split('/')
                if len(pk_names) != len(pk_values):
                    return {'message': 'Invalid primary key values'}, 400
                pk = dict(zip(pk_names, pk_values))
                row = session.query(model).filter_by(**pk).first()
                if row is None:
                    return {"message": "Row not found"}, 400
                return row.to_dict(), 200
            except Exception as e:
                session.rollback()
                return {'message': str(e)}, 400
            finally:
                session.close()


class Search(Resource):
    def get(self, table_name):
        model = get_model_class(table_name)
        if model is None:
            return {"message": "Invalid table name"}, 400
        with Session() as session:
            try:
                key, value = next(iter(request.args.items()))
                rows = session.query(model).filter_by(**{key: value}).all()
                result = [row.to_dict() for row in rows]
                return {'data': result}, 200
            except Exception as e:
                session.rollback()
                return {'message': str(e)}, 400
            finally:
                session.close()


def load_views():
    api.add_resource(Insert, '/api/v1/<string:table_name>')
    api.add_resource(Update, '/api/v1/<string:table_name>')
    api.add_resource(Search, '/api/v1/<string:table_name>')
    api.add_resource(Delete, '/api/v1/<string:table_name>/<path:pks>')
    api.add_resource(Query, '/api/v1/<string:table_name>/<path:pks>')
